let availset = new Set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_')

function objToMap(obj){
	let retMap = new Map()
	for(let key of Object.keys(obj)){
		retMap.set(key, obj[key])
	}
	return retMap
}

function mapToObj(map){
	let retObj = Object.create(null)
	for(let [key, value] of map){
		retObj[key] = value
	}
	return retObj
}

function dumpMap(map){
	return JSON.stringify(mapToObj)
}

function loadMap(source){
	return objToMap(JSON.parse(source))
}

function checkUsername(username){
	for(let i = 0; i < username.length; i++){
		if(!availset.has(username[i])){
			return false
		}
	}
	return true
}

class AppDelegate{
	constructor(){
		if(window.localStorage.userlist == null){
			window.localStorage.userlist = '{}'
		}
		this.userlist = JSON.parse(window.localStorage.userlist)
		this.currentUser = null

		if(window.localStorage.adminList == null){
			window.localStorage.adminList = '[]'
		}
		this.adminList = new Set(JSON.parse(window.localStorage.adminList))

		if(window.localStorage.accountList == null || window.localStorage.accountList == '[null]'){
			window.localStorage.accountList = '[]'
		}
		this.accountStringList = JSON.parse(window.localStorage.accountList)
		this.accountList = []
		for(let accountString of this.accountStringList){
			this.accountList.push(this.decodeAccount(accountString))
		}
		this.accountIDList = null
	}

	synchronizeUserlist(){
		window.localStorage.userlist = JSON.stringify(this.userlist)
		window.localStorage.adminList = JSON.stringify(Array.from(this.adminList))
	}

	synchronizeAccounts(){
		window.localStorage.accountList = JSON.stringify(this.accountStringList)
	}

	/* User delegate */

	createUser(username, password){
		if(this.userlist[username]){
			return "用户名已经存在!"
		}
		if(!checkUsername(username)){
			return "用户名包含非法字符!"
		}
		this.userlist[username] = password
		this.loginUser(username, password)
		this.synchronizeUserlist()
	}

	amIAdmin(username){
		return this.adminList.has(username)
	}

	createAdmin(name, password){
		if(this.userlist[name]){
			return "用户名已经存在!"
		}
		this.userlist[name] = password
		this.adminList.add(name)
		this.loginUser(name, password)
		this.synchronizeUserlist
	}

	loginUser(username, password){
		if(this.userlist[username] == undefined){
			return "用户名不存在!"
		}
		if(this.userlist[username] != password){
			return "密码不正确!"
		}
		this.currentUser = {
			username: username,
			password: password
		}
		this.accountIDList = []
		for(let i = 0; i < this.accountList.length; i++){
			if(this.accountList[i]['owner'] == username){
				this.accountIDList.push(i)
			}
		}
		return null
	}

	logoutUser(){
		this.currentUser = null
		this.accountIDList = null
	}

	changePassword(username, oldp, newp){
		if(oldp == newp){
			return "新旧密码相同!"
		}
		if(!this.userlist[username]){
			return "用户不存在!"
		}
		if(this.userlist[username] != oldp){
			return "密码不匹配!"
		}
		this.userlist[username] = newp
		this.synchronizeUserlist()
		return null
	}

	encodeAccount(account){
		let owner = account.owner
		let amount = account.amount
		let timeStamp = account.timeStamp
		let purpose = account.purpose
		let cleared = account.cleared
		cleared = cleared ? 1 : 0
		let encoded = `${owner}#${amount}#${timeStamp}#${purpose}#${cleared}`
		return encoded
	}

	addAccount(account){
		account.cleared = false
		account.owner = this.currentUser.username
		let encoded = this.encodeAccount(account)
		console.log(encoded)
		this.accountStringList.push(encoded)
		this.accountList.push(this.decodeAccount(encoded))
		this.accountIDList.push(this.accountList.length - 1)
		this.synchronizeAccounts()
		return this.accountList.length
	}

	decodeAccount(accountString){
		// returns an object.
		let tempArr = accountString.split('#')
		let c = parseInt(tempArr[4]) == 1
		return {
			owner: tempArr[0],
			amount: parseFloat(tempArr[1]),
			timeStamp: parseInt(tempArr[2]),
			purpose: tempArr[3],
			cleared: c
		}
	}

	getAccount(accountID){
		if(accountID < 0 || accountID >= this.accountList.length){
			return null
		}
		return this.accountList[accountID]
	}

	clearAccount(accountID){
		this.accountList[accountID].cleared = true
		this.accountStringList[accountID] = this.encodeAccount(this.accountList[accountID])
		this.synchronizeAccounts()
	}

	getAccountIDList(){
		return this.accountIDList
	}

	modifyAccount(accountID, target){
		// insert code here.
	}

	deleteAccount(accountID){
		// insert code here.
	}
}

export {AppDelegate}